Mybatis操作mysql 8的Json字段类型

您所在的位置:网站首页 mybatis 生成json配置 Mybatis操作mysql 8的Json字段类型

Mybatis操作mysql 8的Json字段类型

2024-06-30 15:38| 来源: 网络整理| 查看: 265

Json字段是从mysql 5.7起加进来的全新的字段类型,现在我们看看在什么情况下使用该字段类型,以及用mybatis如何操作该字段类型

一般来说,在不知道字段的具体数量的时候,使用该字段是非常合适的,比如说——商品的无限属性。

现在我们来假设这么一个场景,在商品的二级分类中给商品定义足够多的属性,我们先设计属性的类

代码语言:javascript复制/** * 商品自定义属性 */ @NoArgsConstructor @AllArgsConstructor public class OtherProperty implements Serializable { @Getter @Setter private Long id; //属性id @Getter @Setter private FormType formType; //前端使用的表单类型 @Getter @Setter private String name; //属性名称 @Getter @Setter private String unit; //单位 @Getter @Setter private String values; //可选值以@分隔,如配件@车品 @Getter private List valueList = new ArrayList(); //对可选值的取值列表 @Getter @Setter private String defaultValue; //可选值中的默认值 @Getter @Setter private boolean search; //是否可搜索 @Getter @Setter private boolean mustWrite; //是否必录 @Getter @Setter private Boolean used = false; //是否已经在商品中使用,已使用该属性则不允许修改 public OtherProperty changeValuesToList() { String[] split = this.values.split("@"); for (String value : split) { this.valueList.add(value); } this.values = null; return this; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; OtherProperty that = (OtherProperty) o; if (!id.equals(that.id)) return false; if (search != that.search) return false; if (mustWrite != that.mustWrite) return false; if (formType != that.formType) return false; if (!name.equals(that.name)) return false; if (unit != null ? !unit.equals(that.unit) : that.unit != null) return false; if (values != null ? !values.equals(that.values) : that.values != null) return false; return defaultValue != null ? defaultValue.equals(that.defaultValue) : that.defaultValue == null; } @Override public int hashCode() { int result = id.hashCode() + formType.hashCode() + name.hashCode(); result = result + (unit != null ? unit.hashCode() : 0); result = result + (values != null ? values.hashCode() : 0); result = result + (defaultValue != null ? defaultValue.hashCode() : 0); result = result + (search ? 1 : 0); result = result + (mustWrite ? 1 : 0); return result; } }

其中formType为枚举类型

代码语言:javascript复制public enum FormType implements Localisable { TYPE1("文本框"), TYPE2("下拉框"), TYPE3("单选框"), TYPE4("复选框"), TYPE5("多行文本框"); private String value; private FormType(String value) { this.value = value; } @Override public String getValue() { return this.value; } }

我们来看一下商品分类的部分代码

代码语言:javascript复制@AllArgsConstructor @NoArgsConstructor public class ProviderProductLevel implements Provider,Serializable

其中包含一个商品属性对象的列表

代码语言:javascript复制@Getter @Setter private List otherProperties;

部分操作源码如下

代码语言:javascript复制/** * 通过二级配件分类id查找其包含的所有其他属性 * @param * @return */ public List findOtherProperties() { if (this.level == 2) { LevelDao levelDao = SpringBootUtil.getBean(LevelDao.class); String ids = levelDao.findIdsByLevel2Id(this.id); return levelDao.findOtherProperties(ids); } return null; } /** * 在二级配件分类中删除其他属性的id * @param paramIds * @return */ public boolean deletePropertyIdfromLevel(String paramIds) { if (this.level == 2) { LevelDao levelDao = SpringBootUtil.getBean(LevelDao.class); String ids = levelDao.findIdsByLevel2Id(this.id); String[] idsArray = ids.split(","); List idsList = Arrays.asList(idsArray); List contentIdsList = new ArrayList(); contentIdsList.addAll(idsList); String[] paramArray = paramIds.split(","); List paramList = Arrays.asList(paramArray); if (contentIdsList.containsAll(paramList)) { contentIdsList.removeAll(paramList); } if (contentIdsList.size() > 0) { StringBuilder builder = new StringBuilder(); contentIdsList.stream().forEach(eachId -> builder.append(eachId + ",")); String newIds = builder.toString().substring(0, builder.toString().length() - 1); levelDao.addOtherPropertiesToLevel(new ParamOtherPropertiesId(newIds, this.id)); }else { levelDao.addOtherPropertiesToLevel(new ParamOtherPropertiesId("",this.id)); } return true; } return false; }代码语言:javascript复制/** * 展示某二级配件分类的所有其他属性 * @param id * @return */ @SuppressWarnings("unchecked") @Transactional @GetMapping("/productprovider-anon/showproperties") public Result showOtherProperties(@RequestParam("id") Long id) { Provider level2 = levelDao.findLevel2(id); return Result.success(((ProviderProductLevel)level2).findOtherProperties()); } /** * 修改某二级配件分类的其他属性 * @param id * @param otherProperties * @return */ @SuppressWarnings("unchecked") @Transactional @PostMapping("/productprovider-anon/changeother") public Result changeOtherProperties(@RequestParam("id") Long id,@RequestBody List otherProperties) { //获取配件二级分类对象 Provider level2 = levelDao.findLevel2(id); //获取未使用的配件二级分类的其他属性(没有任何商品使用过该属性) List unUsedList = Optional.ofNullable(((ProviderProductLevel) level2).getOtherProperties()).map(otherProperties1 -> otherProperties1.stream()) .orElse(new ArrayList().stream()) .filter(otherProperty -> !otherProperty.getUsed()) .collect(Collectors.toList()); //获取已使用的配件二级分类的其他属性 List usedIdList = Optional.ofNullable(((ProviderProductLevel) level2).getOtherProperties()).map(otherProperties1 -> otherProperties1.stream()) .orElse(new ArrayList().stream()) .filter(otherProperty -> otherProperty.getUsed()) .map(OtherProperty::getId) .collect(Collectors.toList()); //在传递回来的配件二级分类其他属性中校对没有修改过的,没有使用过的其他属性,只对修改过的,没有使用过的其他属性进行 //存储,否则不处理 List changeList = otherProperties.stream().filter(otherProperty -> Optional.ofNullable(otherProperty.getId()).isPresent()) .filter(otherProperty -> !unUsedList.contains(otherProperty)) .filter(otherProperty -> !usedIdList.contains(otherProperty.getId())) .peek(otherProperty -> otherPropertyDao.deleteOtherPropertiesById(otherProperty.getId())) .collect(Collectors.toList()); if (changeList.size() > 0) { StringBuilder builder = new StringBuilder(); changeList.stream().map(OtherProperty::getId).forEach(eachId -> builder.append(eachId + ",")); String newIds = builder.toString().substring(0, builder.toString().length() - 1); ((ProviderProductLevel) level2).deletePropertyIdfromLevel(newIds); ((ProviderProductLevel) level2).addOtherProperties(changeList); } //获取新增的其他属性进行追加到配件二级分类的其他属性中 List newList = otherProperties.stream().filter(otherProperty -> !Optional.ofNullable(otherProperty.getId()).isPresent()) .peek(otherProperty -> otherProperty.setId(idService.genId())) .collect(Collectors.toList()); ((ProviderProductLevel) level2).addOtherProperties(newList); return Result.success("修改成功"); }

在进行一番增删改查后,数据库中的数据大致如下

我们查高级项链的所有属性的结果如下

现在我们要在属于该商品分类中添加商品,商品类定义大致如下

代码语言:javascript复制@Data @NoArgsConstructor public class ProviderProduct implements Provider { private Product product; //配件元信息对象 private String code; //配件编码 private Brand brand; //品牌 private String details; //配件图文说明 private String levelName; //二级配件分类名称 private DefaultProvider provider; //配件商 private ExtBeanWrapper otherValues; //其他属性集合 }

其中对应于属性列表的字段为otherValues,这个值正是我们要存入数据库的Json字段类型映射。

商品的数据库表结构如下

要使用mybatis的数据对Json字段类型的转换,可以先引用一个网上写好的转换器,当然也可以自己写

pom

代码语言:javascript复制 com.github.jeffreyning extcol 0.0.1-RELEASE

配置文件中添加 type-handlers-package: com.nh.micro.ext.th

代码语言:javascript复制mybatis: type-aliases-package: com.cloud.model.productprovider type-handlers-package: com.nh.micro.ext.th mapper-locations: classpath:/mybatis-mappers/* configuration: mapUnderscoreToCamelCase: true

在mapper文件中写入一段插入语句

代码语言:javascript复制 insert into product (id,name,code,model,normal_price,price_begin,product_imgs,details,brand_id,other_property_value) values (#{product.id},#{product.name},#{code},#{product.model},#{product.price.normalPrice}, 1 0 , #{product.productImgs}, #{details}, #{brand.id}, #{otherValues,jdbcType=VARCHAR} )

对应商品分类的每一个自定义属性,我们可以先拿到该自定义属性的id,然后以该id,取值为键值对进行插入

{ "product":{ "name":"AAAA", "model":"AAAAA", "price":{ "normalPrice":199, "begin":false }, "productImgs":"http://123.433.567.988" }, "code":"0001", "details":"", "brand":{ "id":1, "name":"飞利浦" }, "otherValues":{ "innerMap":{ "2459623566996408120":"10", "2459623566996409144":"呼和浩特", "2459623566996410168":"飞利浦", "2459623566996411192":"国际", "2459623566996412216":"包邮" } } }

执行之后,数据库的数据如下

该插件的数据类和转换器的源码如下,其实也是很简单的

代码语言:javascript复制public class ExtBeanWrapper { public ExtBeanWrapper() { }; public ExtBeanWrapper(Object entity) { this.setObj(entity); } private Map innerMap = new HashMap(); public Map getInnerMap() { return innerMap; } public void setInnerMap(Map innerMap) { this.innerMap = innerMap; } public void setObj(Object entity) { if (entity == null) { innerMap = null; } JSON jobj = (JSON) JSON.toJSON(entity); innerMap = JSON.toJavaObject(jobj, Map.class); } public Object getObj() { if (innerMap == null) { return null; } JSON jobj = (JSON) JSON.toJSON(innerMap); Map entity = JSON.toJavaObject(jobj, Map.class); return entity; } public Object getObj(Class targetClass) { if (innerMap == null) { return null; } JSON jobj = (JSON) JSON.toJSON(innerMap); Object entity = JSON.toJavaObject(jobj, targetClass); return entity; } }代码语言:javascript复制MappedTypes(com.nh.micro.ext.ExtBeanWrapper.class) @MappedJdbcTypes(JdbcType.VARCHAR) public class TagToJsonTypeHandler extends BaseTypeHandler { private Map jsonToMap(String value) { if (value == null || "".equals(value)) { return Collections.emptyMap(); } else { return JSON.parseObject(value, new TypeReference() { }); } } @Override public void setNonNullParameter(PreparedStatement ps, int i, ExtBeanWrapper parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, JSON.toJSONString(parameter.getInnerMap())); } public boolean isJson(String value){ if(value==null || "".equals(value)){ return false; }else{ if(value.startsWith("{")){ return true; } } return false; } @Override public ExtBeanWrapper getNullableResult(ResultSet rs, String columnName) throws SQLException { String value=rs.getString(columnName); Map innerMap=jsonToMap(value); ExtBeanWrapper extBeanTag=new ExtBeanWrapper(); extBeanTag.setInnerMap(innerMap); return extBeanTag; } @Override public ExtBeanWrapper getNullableResult(ResultSet rs, int columnIndex) throws SQLException { String value=rs.getString(columnIndex); Map innerMap=jsonToMap(value); ExtBeanWrapper extBeanTag=new ExtBeanWrapper(); extBeanTag.setInnerMap(innerMap); return extBeanTag; } @Override public ExtBeanWrapper getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { String value=cs.getString(columnIndex); Map innerMap=jsonToMap(value); ExtBeanWrapper extBeanTag=new ExtBeanWrapper(); extBeanTag.setInnerMap(innerMap); return extBeanTag; } }

现在我们来看一下如何将该Json字段从数据库取出,还是以上面的案例为例,先在mapper文件中定义一组resultMap

代码语言:javascript复制

这里稍微解释一下,price里的begin是boolean类型,price_begin在数据库中是整形,有一个转换器,代码如下

代码语言:javascript复制public class BoolIntTypeHandler extends BaseTypeHandler { @Override public void setNonNullParameter(PreparedStatement ps, int i, Boolean parameter, JdbcType jdbcType) throws SQLException { ps.setBoolean(i,parameter); } @Override public Boolean getNullableResult(ResultSet rs, String columnName) throws SQLException { int value = rs.getInt(columnName); if (rs.wasNull()) { return false; }else { if (value == 0) { return false; }else if (value == 1) { return true; } } return false; } @Override public Boolean getNullableResult(ResultSet rs, int columnIndex) throws SQLException { int value = rs.getInt(columnIndex); if (rs.wasNull()) { return false; }else { if (value == 0) { return false; }else if (value == 1) { return true; } } return false; } @Override public Boolean getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { int value = cs.getInt(columnIndex); if (cs.wasNull()) { return false; }else { if (value == 0) { return false; }else if (value == 1) { return true; } } return false; } }

品牌这里有一个查找

代码语言:javascript复制 select id,code,name,sort,log_url logoUrl from brand id=#{brand_id}

配件二级分类名称

代码语言:javascript复制 select name from product_level id=#{level_id}

配件商信息

代码语言:javascript复制 代码语言:javascript复制 select a.id,a.name,b.code from product_provider a inner join default_provider b on a.id=b.id a.id=#{default_provider_id}

当然我们的重点还是otherValues这里

代码语言:javascript复制

获取数据的全部select代码如下

代码语言:javascript复制 select id,code,name,model,brand_id,normal_price,level_id,default_provider_id,other_property_value from product id=#{id}

获取出来的数据如下

{ "code": 200, "data": { "brand": { "code": "001", "id": 1, "logoUrl": "http://123.456.789", "name": "飞利浦", "sort": 1 }, "code": "0001", "levelName": "高级项链", "otherValues": { "innerMap": { "2459623566996411192": "国际", "2459623566996408120": "10", "2459623566996409144": "呼和浩特", "2459623566996410168": "飞利浦", "2459623566996412216": "包邮" }, "obj": { "2459623566996410168": "飞利浦", "2459623566996411192": "国际", "2459623566996408120": "10", "2459623566996409144": "呼和浩特", "2459623566996412216": "包邮" } }, "product": { "id": 2459722970793247544, "model": "AAAAA", "name": "AAAA", "onShelf": false, "price": { "begin": false, "normalPrice": 199 } }, "provider": { "code": "0001", "productProvider": { "id": 2459698718186668856, "name": "大众4S店", "productList": [] }, "status": false } }, "msg": "操作成功" }

当然我们这里要把其他属性的id替换成用户能看懂的其他属性的名称

代码语言:javascript复制@Override public Provider findProduct(Long id) { ProductDao productDao = SpringBootUtil.getBean(ProductDao.class); OtherPropertyDao otherPropertyDao = SpringBootUtil.getBean(OtherPropertyDao.class); Provider product = productDao.findProductById(id); Map map = ((ProviderProduct) product).getOtherValues().getInnerMap(); Map insteadMap = new HashMap(); for (Object key : map.keySet()) { log.info("键名为:" + String.valueOf(key)); String name = otherPropertyDao.findNameById(Long.parseLong(String.valueOf(key))); insteadMap.put(name,(String) map.get(key)); } ((ProviderProduct) product).getOtherValues().setObj(insteadMap); return product; }

最后我们获取的结果为

{ "code": 200, "data": { "brand": { "code": "001", "id": 1, "logoUrl": "http://123.456.789", "name": "飞利浦", "sort": 1 }, "code": "0001", "levelName": "高级项链", "otherValues": { "innerMap": { "商品等级": "国际", "运费设置": "包邮", "生产厂家": "飞利浦", "包装规格": "10", "商品产地": "呼和浩特" }, "obj": { "$ref": "$.data.otherValues.innerMap" } }, "product": { "id": 2459722970793247544, "model": "AAAAA", "name": "AAAA", "onShelf": false, "price": { "begin": false, "normalPrice": 199 } }, "provider": { "code": "0001", "productProvider": { "id": 2459698718186668856, "name": "大众4S店", "productList": [] }, "status": false } }, "msg": "操作成功" }



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3